// -*- coding: utf-8 -*-

#ifdef __cplusplus

#ifndef __HYBRID_PARSER__
#define __HYBRID_PARSER__

#include <iostream>
#include <string>
#include <memory>
#include <map>

#include <boost/shared_ptr.hpp>

#include "elisa/elisa_constraint.h"
#include "elisa/elisa_constant.h"
#include "elisa/elisa_real_expr.h"
#include "elisa/elisa_natural_interval_form.h"
//#include "elisa/hybrid/hybrid.h"
#include "elisa/hybrid/hybrid_model.h"
#include "elisa/hybrid/hybrid_var.h"
//#include "hybrid_expr_visitor.h"

namespace elisa 
{

class location;

class HybridLexer;
typedef boost::shared_ptr<HybridLexer> LexerPtr;

//typedef boost::shared_ptr<elisa::Constant const> ConstPtr;
//typedef std::map<string, ConstPtr> ConstMap;
typedef boost::shared_ptr<elisa::RealExpr> ExprPtr;
typedef std::map<string, ExprPtr> ConstMap;
typedef boost::shared_ptr<elisa::ContVar> VarPtr;
typedef std::map<string, VarPtr> VarMap;

typedef boost::shared_ptr<elisa::RealExpr> ExprPtr;
typedef std::map<string, ExprPtr> DExprMap;


template<typename T>
class HybridExprVisitor;

class HybridParser 
{
public:
	HybridParser();

	bool parseStream(std::istream& in);
	bool parseFile(const char *filename);
	bool parseString(const std::string& str);

	LexerPtr lexer() {
		return m_lexer;
	}

	void error(const elisa::location& l, const std::string& s);
	void error(const std::string& s);

	ConstMap& constants() {
		return m_constMap;
	}

	VarMap& variables() {
		return m_varMap;
	}

	Interval& time() {
		return m_time;
	}

	DExprMap& dExprMap() {
		return m_dExprMap;
	}

	ExprPtr& gExpr() {
		return m_gExpr;
	}

	DExprMap& rExprMap() {
		return m_rExprMap;
	}

	/** 連続制約の定義 
	 *
	 * staticにしないとうまくいかないらしい
	 */
	template<typename T> 
	static void dFunc(int n, T *dv, const T *v, T t, void *param)
	{
		DExprMap::iterator deit(m_instance->dExprMap().begin());
		for (int i(0); deit != m_instance->dExprMap().end(); ++deit, ++i) {
			HybridExprVisitor<T> vst(*m_instance, n, dv, v, t, param);
			vst.visit(*deit->second->rep());
			dv[i] = *vst.value();
		}
	}

	/** ガード制約の定義 */
	template<typename T> 
	T gFunc(const std::vector<T>& vars, const T& t)
	{
		HybridExprVisitor<T> vst(*this, vars, t);
		vst.visit(*m_gExpr->rep());
		return *vst.value();
	}

	/*
	Interval rFunc(const std::string& name, const std::vector<RealExpr>& vars)
	{
		HybridExprVisitor<RealExpr> vst(*this, vars);
		vst.visit(*m_rExprMap[name]->rep());
		RealExpr e(*vst.value());
		NaturalIntervalFormVisitor v;
		v.visit(*e.rep());
		return v.node()->eval();
	}
	*/

	int toVarIndex(const std::string& name) {
		int i(0);
		VarMap::iterator vit(m_varMap.begin());
		for (; vit != m_varMap.end(); ++vit, ++i) {
			if (vit->first == name)
				break;
		}
		return i;
	}

private:
	bool parse();

	LexerPtr m_lexer;
	ConstMap m_constMap;
	VarMap m_varMap;

	Interval m_time;
	
	DExprMap m_dExprMap;
	ExprPtr m_gExpr;
	DExprMap m_rExprMap;

	static HybridParser *m_instance;
};

}

#endif /* __HYBRID_PARSER__ */
#endif /* __cplusplus */
